﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using FeiraGame_XNA.src.core;

namespace FeiraGame_XNA
{
    /// <summary>
    /// Classe Responsavel pelos quadradinhos(Titles) do Mapa. Essa Classe eh pura matematica de calculos dos titles e de seu Draw. Portanto nao possuira tantos comentarios.
    /// </summary>
    public static class TileMap
    {
        #region Tamanho do Mapa e dos Tiles
        public const int TileWidth = 32;
        public const int TileHeight = 32;
        public const int MapWidth = 50;
        public const int MapHeight = 20;
        #endregion

        #region Imagem dos Tiles
        static private Texture2D texture;
        #endregion

        #region Lista dos Tiles e Array do Mapa
        static public List<Tile> tiles = new List<Tile>();
        #endregion

        static public void Initialize(Texture2D tileTexture)
        {
            texture = tileTexture;
            //A lista de tiles a seguir conterá a posição dos tiles na spritesheet
            tiles.Clear();
            #region Setagens do que eh cada quadrado dentro da Array
            tiles.Add(new Tile(new Rectangle(0, 0, TileWidth, TileHeight), false, false, false, false)); //Empty
            tiles.Add(new Tile(new Rectangle(32, 0, TileWidth, TileHeight), true, false, true, false));   //PlatformStart
            tiles.Add(new Tile(new Rectangle(64, 0, TileWidth, TileHeight), true, false, true, false));   //PlatformMiddle
            tiles.Add(new Tile(new Rectangle(96, 0, TileWidth, TileHeight), true, false, true, false));   //PlatformEnd
            tiles.Add(new Tile(new Rectangle(128, 0, TileWidth, TileHeight), true, true, false, false)); //Wall
            tiles.Add(new Tile(new Rectangle(160, 0, TileWidth, TileHeight), true, false, true, false)); //Floor
            #endregion
        }

        /// <summary>
        /// Informa qual é o tile responsável pelo pixelX (posição horizontal)
        /// </summary>
        static public int GetSquareByPixelX(int pixelX)
        {
            return pixelX / TileWidth;
        }

        /// <summary>
        /// Informa qual é o tile responsável pelo pixelY (posição vertical)
        /// </summary>
        static public int GetSquareByPixelY(int pixelY)
        {
            return pixelY / TileHeight;
        }

        /// <summary>
        /// Informa qual é o tile que ocupa determinado pixel
        /// </summary>
        static public Vector2 GetSquareAtPixel(Vector2 pixelLocation)
        {
            return new Vector2(
                GetSquareByPixelX((int)pixelLocation.X),
                GetSquareByPixelY((int)pixelLocation.Y));
        }

        /// <summary>
        /// Retorna o centro do tile que ocupa a posição (squareX,squareY) no espaço.
        /// </summary>
        static public Vector2 GetSquareCenter(int squareX, int squareY)
        {
            return new Vector2(
                (squareX * TileWidth) + (TileWidth / 2),
                (squareY * TileHeight) + (TileHeight / 2));
        }

        /// <summary>
        /// Overload do método anterior, podendo passar um vector.
        /// </summary>
        static public Vector2 GetSquareCenter(Vector2 square)
        {
            return GetSquareCenter((int)square.X, (int)square.Y);
        }

        /// <summary>
        /// Retorna um retângulo contendo a posição de um tile e o seu tamanho
        /// </summary>
        static public Rectangle SquareWorldRectangle(int x, int y)
        {
            return new Rectangle(x * TileWidth, y * TileHeight, TileWidth, TileHeight);
        }

        /// <summary>
        /// Overload do método anterior, podendo passar um vector
        /// </summary>
        static public Rectangle SquareWorldRectangle(Vector2 square)
        {
            return SquareWorldRectangle((int)square.X, (int)square.Y);
        }

        /// <summary>
        /// Retorna o tile na posição (x,y) em relação a cãmera
        /// </summary>
        static public Rectangle SquareScreenRectangle(int x, int y)
        {
            return Camera.Transform(SquareWorldRectangle(x, y));
        }

        /// <summary>
        /// Overload do método anterior podendo passar um vector
        /// </summary>
        static public Rectangle SquareScreenRectangle(Vector2 square)
        {
            return SquareScreenRectangle((int)square.X, (int)square.Y);
        }

        /// <summary>
        /// Retorna o tipo de tile na posição (x,y) do array ou -1 se a posição for maior ou menor que o array.
        /// </summary>
        static public int GetTileAtSquare(int tileX, int tileY)
        {
            if ((tileX >= 0) && (tileX < MapWidth) &&
                (tileY >= 0) && (tileY < MapHeight))
            {
                return GameWorld.current_level_array[tileY, tileX];
                
            }
            else
            {
                return -1; //Tile inválido
            }
        }

        /// <summary>
        /// Seta o tipo de tile no array do mapa.
        /// </summary>
        static public void SetTileAtSquare(int tileX, int tileY, int tile)
        {
            if ((tileX >= 0) && (tileX < MapWidth) &&
                (tileY >= 0) && (tileY < MapHeight))
            {
                GameWorld.current_level_array[tileY, tileX] = tile;
            }
        }

        /// <summary>
        /// Retorna o tipo de tile na posição (x,y) do mapa.
        /// </summary>
        static public int GetTileAtPixel(int pixelX, int pixelY)
        {
            return GetTileAtSquare(GetSquareByPixelX(pixelX), GetSquareByPixelY(pixelY));
        }

        /// <summary>
        /// Overload do método anterior podendo passar um vector.
        /// </summary>
        static public int GetTileAtPixel(Vector2 pixelLocation)
        {
            return GetTileAtPixel((int)pixelLocation.X, (int)pixelLocation.Y);
        }

        /// <summary>
        /// Retorna se o tipo de tile na posição (x,y) do array é uma plataforma.
        /// </summary>
        static public bool IsPlatformTile(int tileX, int tileY)
        {
            int tileIndex = GetTileAtSquare(tileX, tileY);
            return (tileIndex >= (int)Tile.types.PlatformStart && tileIndex <= (int)Tile.types.PlatformEnd);
        }

        /// <summary>
        /// Overload do método anterior podendo passar um vector.
        /// </summary>
        static public bool IsPlatformTile(Vector2 square)
        {
            return IsPlatformTile((int)square.X, (int)square.Y);
        }

        /// <summary>
        /// Retorna se o tipo de tile na posição (x,y) do mapa é uma plataforma.
        /// </summary>
        static public bool IsPlatformTileByPixel(Vector2 pixelLocation)
        {
            return IsPlatformTile(GetSquareByPixelX((int)pixelLocation.X),
                            GetSquareByPixelY((int)pixelLocation.Y));
        }

        /// <summary>
        /// Retorna se o tipo de tile na posição (x,y) do array é uma parede.
        /// </summary>
        static public bool IsWallTile(int tileX, int tileY)
        {
            int tileIndex = GetTileAtSquare(tileX, tileY);
            return tileIndex == (int)Tile.types.Wall;
        }

        /// <summary>
        /// Overload do método anterior podendo passar um vector.
        /// </summary>
        static public bool IsWallTile(Vector2 square)
        {
            return IsWallTile((int)square.X, (int)square.Y);
        }

        /// <summary>
        /// Retorna se o tipo de tile na posição (x,y) do mapa é uma parede.
        /// </summary>
        static public bool IsWallTileByPixel(Vector2 pixelLocation)
        {
            return IsWallTile(GetSquareByPixelX((int)pixelLocation.X),
                            GetSquareByPixelY((int)pixelLocation.Y));
        }

        /// <summary>
        /// Retorna se o tipo de tile na posição (x,y) do array é "vazio".
        /// </summary>
        static public bool IsEmptyTile(int tileX, int tileY)
        {
            int tileIndex = GetTileAtSquare(tileX, tileY);
            return tileIndex == (int)Tile.types.Empty;
        }

        /// <summary>
        /// Overload do método anterior podendo passar um vector.
        /// </summary>
        static public bool IsEmptyTile(Vector2 square)
        {
            return IsEmptyTile((int)square.X, (int)square.Y);
        }

        /// <summary>
        /// Retorna se o tipo de tile na posição (x,y) do mapa é "vazio".
        /// </summary>
        static public bool IsEmptyTileByPixel(Vector2 pixelLocation)
        {
            return IsEmptyTile(GetSquareByPixelX((int)pixelLocation.X),
                            GetSquareByPixelY((int)pixelLocation.Y));
        }

        /// <summary>
        /// Percorre todo o array da fase e desenha os tiles no mapa se o valor
        /// dos mesmos for maior que zero.
        /// </summary>
        static public void Draw(SpriteBatch spriteBatch)
        {
            int startX = GetSquareByPixelX((int)Camera.Position.X);
            int endX = GetSquareByPixelX((int)Camera.Position.X + Camera.ViewPortWidth);
            
            int startY = GetSquareByPixelY((int)Camera.Position.Y);
            int endY = GetSquareByPixelY((int)Camera.Position.Y + Camera.ViewPortHeight);

            for (int x = startX; x <= endX; x++)
            {
                
                for (int y = startY; y <= endY; y++)
                {
                    if ((x >= 0) && (y >= 0) && (x < MapWidth) && (y < MapHeight))
                    {
                        if (GetTileAtSquare(x, y) >= 0)
                        {
                            spriteBatch.Draw(texture, SquareScreenRectangle(x, y),
                                    tiles[GetTileAtSquare(x, y)].RectPosition, Color.White);
                        }
                    }
                }
            }
        }
    }
}
